﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using System.Security;
using System.Security.Permissions;
using MPI;

namespace Dwarf.Managed
{
    /// <summary>
    /// User interface for solving the Sparse Linear Algebra Problem.
    /// </summary>
    class Program
    {
        // <summary>
        /// The settings for this dwarf.
        /// </summary>
        static private Settings settings;

        /// <summary>
        /// Get settings from the command line.
        /// </summary>
        /// <param name="args">
        /// Cli params.
        /// </param>
        /// <param name="slasolver">
        /// Instance of Solver.
        /// </param>
        static void getSettings(String[] args, Solver slasolver) 
        {
            bool error = false;
            if (Communicator.world.Rank == Settings.ROOT_PROCESS)
            {
                try
                {
                    settings = new Settings();
                    settings.Init(args, slasolver);         //Parse all arguments for dwarf.
                } catch (Exception ex) {
                    Console.WriteLine(ex.Message);                    
                    error = true;                  
                }
            }

            //Distribute error if that occurred while parsing.
            MPI.Communicator.world.Broadcast(ref error, Settings.ROOT_PROCESS);
            if (error) throw new Exception("");

            //Distribute number of rows.
            MPI.Communicator.world.Broadcast(ref slasolver.rowNum, Settings.ROOT_PROCESS);

            //Init arrays.
            if (Communicator.world.Rank != Settings.ROOT_PROCESS)
            {
                slasolver.val = new double[slasolver.rowNum];
                slasolver.col_ind = new int[slasolver.rowNum];
                slasolver.vector = new double[slasolver.rowNum];
            }

            //Distribute vector.
            MPI.Communicator.world.Broadcast<double[]>(ref slasolver.vector, Settings.ROOT_PROCESS);
        }

        /// <summary>
        /// Point of the program start.
        /// </summary>
        /// <param name="args">
        /// Cli params.
        /// </param>
        static void Main(String[] args)
        {
            
            try
            {
                using (new MPI.Environment(ref args))                       // MPI Initialization.
                {
                    if (Communicator.world.Size == 1) 
                    { 
                        throw new Exception("Only one mpi process.");
                    }
        
                    Solver slasolver = new Solver();

                    getSettings(args, slasolver);                           // Get settings from the command line.

                    Communicator.world.Barrier();
                    if (Communicator.world.Rank == Settings.ROOT_PROCESS)
                        settings.Start();                                   // Start new time count.
                    //This line of code is used for decrease of input file size.
                    //Such modification would reduce the input file size, 
                    //but the algorithm is still belongs dwarf.
                    //Also this line does not affect the result.
                    for (int k = 0; k < 200; k++)
                    { slasolver.Solve(); }                                     // Solve the current problem.
                    Communicator.world.Barrier();
                    if (Communicator.world.Rank == Settings.ROOT_PROCESS)
                        settings.Finish(slasolver);                         // Stop the time count and write results.

                }
        
            }
            catch (Exception ex) 
            {
                Console.WriteLine(ex.Message);
                //usage();
            }

        }
    }
}
